/**
 * Copyright (c) 2010, iDA MediaFoundry
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * - Neither the name of iDA MediaFoundry nor the names of its contributors may
 *   be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package be.idamf.flash.utils
{
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	
	/**
	 * Utility class to duplicate instances and data.
	 * 
	 * @author Jan Van Coppenolle
	 */
	public final class ObjectCopy
	{
		/**
		 * Performs a deep copy (mx.utils.ObjectUtil.copy() method).
		 * 
		 * @returns A new object graph.
		 */
		public static function deep(object:Object):*
		{
			var bytes:ByteArray = new ByteArray();
		    bytes.writeObject(object);
		    bytes.position = 0;
		    return bytes.readObject();
		}
		
		/**
		 * Performs a shallow copy.
		 * 
		 * @returns A new object graph.
		 */
		public static function shallow(object:Object):*
		{
			var type:XML;
			var name:String;  
			var kind:Class; 
			var copy:Object; 
			var accessor:XML;
			var property:*;
			
			// faster check than going through describeType
			if (object is Array)
				return (object as Array).splice();
			
			type = describeType(object);
			name = type.@name;
			
			switch (name)
			{
				case "int":
				case "uint":
				case "Number":
				case "String":
				case "Boolean":
				
					return object;
				
				case "Object":
				case "flash.utils.Dictionary":
				
					copy = (name == "Object" ? {} : new Dictionary(true));
					
					for (property in object)
						copy[property] = object[property];
						
					return copy;
			}
			
			kind = Class(getDefinitionByName(name));
			copy = new kind();
			
			for each (accessor in type..accessor.(@access == "readwrite"))
				copy[accessor.@name] = object[accessor.@name];
				
			return copy;
		}
		
		/**
		 * Copies the property values from the source object 
		 * to the target object.
		 */
		public static function migrate(source:Object, target:Object):void
		{
			var type:XML;
			var accessor:XML;
			
			type = describeType(source);
			
			for each (accessor in type..accessor.(@access == "readwrite"))
				target[accessor.@name] = source[accessor.@name];
		}
		
		/**
		 * @private
		 */
		public function ObjectCopy()
		{
			throw new Error("Static Class");
		}
	}
}